/*
** Copyright (C) 2009 Zhang Cong <ftofficer@ftofficer.com>
**  
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**  
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**  
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**  
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif // HAVE_CONFIG_H
#include "portable.h"

#include <string.h>
#include <stdlib.h>

#include "liboi.h"
#include "oissh.h"

liboi_err_t liboi_init()
{
#ifdef WIN32
	WSADATA data;
	return WSAStartup(MAKEWORD(1,1), &data);
#endif // WIN32
}

void liboi_cleanup()
{
#ifdef WIN32
	WSACleanup();
#endif // WIN32
}

static liboi_err_t copy_device_location(oi_device_location* source,
                                        oi_device_location* dest)
{
    if ( ! source || ! dest )
        return EINVAL;

    dest->type = source->type;
    dest->address = strdup(source->address);
    if ( ! dest->address )
        return ENOMEM;

    return LIBOI_OK;
}

liboi_err_t oi_find_all(oi_device_location* device_loc,
                        int* device_loc_count)
{
    return LIBOI_E_NOTIMPL;
}

liboi_err_t oi_device_location_free(oi_device_location* dev_loc)
{
    if ( ! dev_loc )
        return EINVAL;

    if ( dev_loc->address )
        free((void*)dev_loc->address);

    free(dev_loc);

    return LIBOI_OK;
}

liboi_err_t oi_device_connect(oi_device_location* dev_loc,
                              oi_device** device)
{
    if ( ! dev_loc || ! device )
        return EINVAL;

    switch ( dev_loc->type )
    {
        case OI_DEVICE_USB_STORAGE:
            // TODO: Implementation for USB storage based OI device.
            return LIBOI_E_NOTIMPL;
            
        case OI_DEVICE_SSH_CONNECTED:
        {
            liboi_err_t err = LIBOI_OK;
            oi_device* new_dev = NULL;

            new_dev = oi_ssh_create_device();
            if ( ! new_dev )
                return ENOMEM;

            copy_device_location(dev_loc, &new_dev->dev_loc);

            err = oi_ssh_connect(new_dev);
            if ( err != LIBOI_OK )
            {
                oi_ssh_free_device(new_dev);
                new_dev = NULL;
            }

            *device = new_dev;
            return err;
        }

        default:
            break;
    }

    return EINVAL;
}

liboi_err_t oi_device_disconnect(oi_device* device)
{
    if ( ! device )
        return EINVAL;

    switch ( device->dev_loc.type )
    {
        case OI_DEVICE_USB_STORAGE:
            // TODO: Implement for USB storage based OI device.
            return LIBOI_E_NOTIMPL;

        case OI_DEVICE_SSH_CONNECTED:
            return oi_ssh_disconnect(device);

        default:
            break;
    }

    return EINVAL;
}

liboi_err_t oi_device_get_info(oi_device* device,
                               oi_device_info* dev_info)
{
    if ( ! device )
        return EINVAL;

    switch ( device->dev_loc.type )
    {
        case OI_DEVICE_USB_STORAGE:
            // TODO: Implement for USB storage based OI device.
            return LIBOI_E_NOTIMPL;

        case OI_DEVICE_SSH_CONNECTED:
            return oi_ssh_get_info(device, dev_info);

        default:
            break;
    }

    return EINVAL;
}

void oi_free_data_buffer(struct data_buffer* data)
{
    if ( data )
    {
        if ( data->data )
        {
            free(data->data);
            data->data = NULL;
        }
        data->length = 0;
    }
}

liboi_err_t oi_exec_in_device(oi_device* device,
                              const char* command,
                              struct data_buffer* stdin_,
                              int* exit_code,
                              struct data_buffer* stdout_,
                              struct data_buffer* stderr_)
{
    if ( ! device )
        return EINVAL;

    switch ( device->dev_loc.type )
    {
        case OI_DEVICE_USB_STORAGE:
            // TODO: Implement for USB storage based OI device.
            return LIBOI_E_NOTIMPL;

        case OI_DEVICE_SSH_CONNECTED:
            return oi_ssh_exec_in_device(device, command, stdin_,
                                         exit_code,
                                         stdout_, stderr_);

        default:
            break;
    }

    return EINVAL;
}


liboi_err_t oi_get_file(oi_device* device,
                        const char* device_file_path,
                        const char* host_file_path)
{
    if ( ! device )
        return EINVAL;

    switch ( device->dev_loc.type )
    {
        case OI_DEVICE_USB_STORAGE:
            // TODO: Implement for USB storage based OI device.
            return LIBOI_E_NOTIMPL;

        case OI_DEVICE_SSH_CONNECTED:
            return oi_ssh_get_file(device, device_file_path, host_file_path);

        default:
            break;
    }

    return EINVAL;
}

liboi_err_t oi_put_file(oi_device* device,
                        const char* host_file_path,
                        const char* device_file_path)
{
    if ( ! device )
        return EINVAL;

    switch ( device->dev_loc.type )
    {
        case OI_DEVICE_USB_STORAGE:
            // TODO: Implement for USB storage based OI device.
            return LIBOI_E_NOTIMPL;

        case OI_DEVICE_SSH_CONNECTED:
            return oi_ssh_put_file(device, host_file_path, device_file_path);

        default:
            break;
    }

    return EINVAL;
}


liboi_err_t oi_device_free(oi_device* device)
{
    if ( ! device )
        return EINVAL;

    switch ( device->dev_loc.type )
    {
        case OI_DEVICE_USB_STORAGE:
            // TODO: Implement for USB storage based OI device.
            return LIBOI_E_NOTIMPL;

        case OI_DEVICE_SSH_CONNECTED:
            oi_ssh_free_device(device);
            return LIBOI_OK;

        default:
            break;
    }

    return EINVAL;
}
